#include "RS485_protocol.h"

#include "common.h"
#include "string.h"
#include "InCall_info.h"
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"
#include "main.h"
#include "A_device.h"
#include "display.h"

#define msg_min_len 9
#define msg_max_len 12

extern osMessageQId queue_key_eventHandle;
extern osSemaphoreId semaphore_update_status;

static msg_content_len_s _msg_len[] = {
    {CMD_sys_info1, 6 + 3},
    //    {CMD_sys_info2, 6 + 3},

    //    {CMD_key_board_info, 9 + 3},
    //    {CMD_key_board_info_reply, 9 + 3}

};

static unsigned char get_msg_content_len(unsigned char cmd)
{
    for (size_t i = 0; i < ARRAYSIZE(_msg_len); i++)
    {
        /* code */
        if (cmd == _msg_len[i].cmd)
            return _msg_len[i].len;
    }
    return 0xff;
}

static bool is_protocol_msg_header(unsigned char val)
{
    for (size_t i = 0; i < ARRAYSIZE(_msg_len); i++)
    {
        /* code */
        if (val == _msg_len[i].cmd)
            return pdTRUE;
    }
    return pdFALSE;
}

int protocol_common_generate(
    unsigned char addr,
    unsigned char *frame,
    unsigned char *const data,
    unsigned char len)
{
    unsigned char frame_index = 0;
    if (!frame | ((!data) && (len > 0)))
    {
        return -1;
    }
    Type_InCall_info *info = get_InCall_info();
    frame[frame_index++] = addr;

    if (len > 0)
    {
        memcpy(&frame[frame_index], data, len);
        frame_index += len;
    }

    unsigned short ret = ModBusCRC16(frame, frame_index);
    frame[frame_index++] = ret;
    frame[frame_index++] = ret >> 8;

    return frame_index;
}

HANDLER(sys_info)
{

    pro_ret ReplyFlagClient = PRO_OK;

    unsigned char reply_data[128];

    unsigned int tick_now = xTaskGetTickCount();

    memset(reply_data, 0, sizeof(reply_data));

    Type_InCall_info *info = get_InCall_info();

    sys_info_data_s *sys_info_data = (sys_info_data_s *)&data[1];

    unsigned char dis_l = sys_info_data->dis_info[0] & 0x3f;
    unsigned char dis_m = (sys_info_data->dis_info[0] >> 6) | ((sys_info_data->dis_info[1] & 0x0f) << 2);
    unsigned char dis_h = (sys_info_data->dis_info[1] >> 4) | ((sys_info_data->dis_info[2] & 0x03) << 4);

    unsigned int dis_data = 0;

    dis_data = sys_info_data->info.data;
    dis_data |= dis_l << 8;
    dis_data |= dis_m << 16;
    dis_data |= dis_h << 24;
    send_display_data(dis_data);
    
    return ReplyFlagClient;
}

static _protocol_struct cmd_list[] = {

    //    {CMD_key_board_info, HANDLER_POINT(CMD_key_board_info)},
    {CMD_sys_info1, HANDLER_POINT(sys_info)},

};

/*
 * 检查CRC是否正确
 * 参数：数据帧
 * return:crc是否争取，true:crc正确，false：crc错误
 */
static bool checkCRC(unsigned char *data, int len)
{
    unsigned short ret = ModBusCRC16(data, len - 2);
    return ((data[len - 2] | ((data[len - 1] << 8))) == ret) ? true : false;
}

/*
 * 协议数据处理函数
 * 参数：485接收到的字节数据
 * return:无返回值
 */

static void data_process(unsigned char *data, unsigned char len)
{

    Type_InCall_info *info = get_InCall_info();

    for (int i = 0; i < ARRAYSIZE(cmd_list); i++)
    {
        if (data[0] == cmd_list[i].cmd)
        {
            cmd_list[i].handler(data);
            break;
        }
    }
}

static bool is_protocol = false;
static unsigned char _recv_buf[260] = {0};
static unsigned int rec_index = 0;
static unsigned char inrec_flag = 0;

int reset_times = 0;

static void reset_flag(void)
{
    is_protocol = false;
    rec_index = 0;
    reset_times++;
    memset(_recv_buf, 0, sizeof(_recv_buf));
}

static char check_inrec(void)
{
    if (inrec_flag > 0)
    {
        if (0 == (--inrec_flag))
        {
            reset_flag();
            return 1;
        }
    }
    return 0;
}

void frame_parse(void)
{
    _UsartDevieStruct *_device = get_485Device();
    Type_InCall_info *info = get_InCall_info();
    unsigned char tmp = 0;
    static int has_communication = 0;
    static int last_communication_tick = 0;

    check_inrec();
    if (has_communication && abs_duration_timeout(xTaskGetTickCount(), last_communication_tick, 60 * 1000 / portTICK_PERIOD_MS))
    {
        //        HAL_NVIC_SystemReset();
        //        while (1)
        //            ;
    }
    while (_device->read(&tmp))
    {
        inrec_flag = 3;
        _recv_buf[rec_index++] = tmp;
        if (is_protocol)
        {
            if (rec_index > msg_max_len)
            {
                reset_flag();
            }
            else if (rec_index >= msg_min_len)
            {
                unsigned char msg_len = get_msg_content_len(_recv_buf[0]);
                if (0xff == msg_len)
                {
                    reset_flag();
                    continue;
                }
                if (rec_index == msg_len) // 接收完成
                {
                    inrec_flag = 0;
                    if (checkCRC(_recv_buf, rec_index))
                    {
                        data_process(_recv_buf, rec_index);
                        has_communication = 1;
                        last_communication_tick = xTaskGetTickCount();
                    }

                    reset_flag();
                }
            }
        }
        else
        {
            if (pdTRUE == is_protocol_msg_header(tmp))
            {
                rec_index = 0;
                _recv_buf[rec_index++] = tmp;
                is_protocol = true;
            }
        }
    }
}
